package com.ybb.production.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ybb.production.domain.GarmentProductionBianfei;
import com.ybb.production.domain.GarmentProductionOrder;
import com.ybb.production.domain.GarmentProductionUserPay;
import com.ybb.production.dto.*;
import com.ybb.production.mapper.GarmentProductionOrderMapper;
import com.ybb.production.mapper.GarmentProductionUserPayMapper;
import com.ybb.production.mapper.GarmentProductionUserPayTemplateMapper;
import com.ybb.production.responce.GarmentPayByCntResp;
import com.ybb.production.responce.GarmentPayDetailResp;
import com.ybb.production.responce.GarmentPayStyleCodeAndProcessResp;
import com.ybb.production.service.IGarmentProductionUserPayService;
import com.yubb.common.constant.CacheConstants;
import com.yubb.common.core.redis.RedisCache;
import com.yubb.common.utils.DateUtils;
import com.yubb.common.utils.ShiroUtils;
import com.yubb.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户工资发放Service业务层处理
 *
 * @author dj
 * @date 2023-09-27
 */
@Service
public class GarmentProductionUserPayServiceImpl implements IGarmentProductionUserPayService {
    @Autowired
    private GarmentProductionUserPayMapper garmentProductionUserPayMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private GarmentProductionBianfeiServiceImpl garmentProductionBianfeiService;

    @Autowired
    private GarmentProductionOrderMapper garmentProductionOrderMapper;

    @Autowired
    private GarmentProductionUserPayTemplateMapper garmentProductionUserPayTemplateMapper;

    /**
     * 查询用户工资发放
     *
     * @param id 用户工资发放主键
     * @return 用户工资发放
     */
    @Override
    public GarmentProductionUserPay selectGarmentProductionUserPayById(Long id) {
        return garmentProductionUserPayMapper.selectGarmentProductionUserPayById(id);
    }

    /**
     * 查询用户工资发放列表
     *
     * @param garmentProductionUserPay 用户工资发放
     * @return 用户工资发放
     */
    @Override
    public List<GarmentProductionUserPay> selectGarmentProductionUserPayList(GarmentProductionUserPay garmentProductionUserPay) {
        return garmentProductionUserPayMapper.selectGarmentProductionUserPayList(garmentProductionUserPay);
    }

    /**
     * 新增用户工资发放
     *
     * @param garmentProductionUserPay 用户工资发放
     * @return 结果
     */
    @Override
    public int insertGarmentProductionUserPay(GarmentProductionUserPay garmentProductionUserPay) {
        garmentProductionUserPay.setCreateTime(DateUtils.getNowDate());
        return garmentProductionUserPayMapper.insertGarmentProductionUserPay(garmentProductionUserPay);
    }

    /**
     * 修改用户工资发放
     *
     * @param garmentProductionUserPay 用户工资发放
     * @return 结果
     */
    @Override
    public int updateGarmentProductionUserPay(GarmentProductionUserPay garmentProductionUserPay) {
        garmentProductionUserPay.setUpdateTime(DateUtils.getNowDate());
        return garmentProductionUserPayMapper.updateGarmentProductionUserPay(garmentProductionUserPay);
    }

    /**
     * 批量删除用户工资发放
     *
     * @param ids 需要删除的用户工资发放主键
     * @return 结果
     */
    @Override
    public int deleteGarmentProductionUserPayByIds(Long[] ids) {
        return garmentProductionUserPayMapper.deleteGarmentProductionUserPayByIds(ids);
    }

    /**
     * 删除用户工资发放信息
     *
     * @param id 用户工资发放主键
     * @return 结果
     */
    @Override
    public int deleteGarmentProductionUserPayById(Long id) {
        return garmentProductionUserPayMapper.deleteGarmentProductionUserPayById(id);
    }

    @Override
    public List<GarmentPayByCntResp> settlementListByQuantity(GarmentProductionPayCntParam userPayParam) {
        List<GarmentPayByCntResp> resps = garmentProductionUserPayMapper.settlementListByQuantity(userPayParam);
        if (resps == null || resps.isEmpty()) {
            return new ArrayList<>();
        }
        // 查询发放情况
        for (GarmentPayByCntResp resp : resps) {
            if (resp.getUnSettleMoney() == null && resp.getSettleMoney() == null) {
                resp.setStatus("0");
                continue;
            }
            double unSettleMoney = Double.parseDouble(resp.getUnSettleMoney());
            double settleMoney = Double.parseDouble(resp.getSettleMoney());
            double totalMoney = Double.parseDouble(resp.getTotalMoney());
            if (unSettleMoney == totalMoney) {
                resp.setStatus("1");
            }
            if (settleMoney > 0 && settleMoney < totalMoney) {
                resp.setStatus("2");
            }
            if (settleMoney == totalMoney) {
                resp.setStatus("3");
            }
            if (resp.getSettleTimeStr() == null) {
                resp.setPayMoney("0");
                continue;
            }
            JSONObject payParam = new JSONObject();
            payParam.put("upId", resp.getUpId());
            payParam.put("settlementTime", resp.getSettleTimeStr());
            double sumPay = garmentProductionUserPayMapper.qryPayMoneyByUpIdAndSettleTime(payParam);
            resp.setPayMoney(StringUtils.roundDoubleToString(sumPay, 2));
            resp.setSettleMoney(Double.parseDouble(resp.getSettleMoney()) - sumPay + "");
            if (Objects.equals(resp.getTotalMoney(), "0.0")) {
                resp.setStatus("0");
            }

        }
        return resps;
    }

    @Override
    public int addPayConfig(List<GarmentProductionCustomizeConfDTO> confDTOList) {
        // 存入redis
        redisCache.setCacheObject(CacheConstants.CUSTOMIZE_CONF, confDTOList);
        return 1;
    }

    @Override
    public List<GarmentProductionCustomizeConfDTO> qryPayConfig() {
        List<GarmentProductionCustomizeConfDTO> confDTOList = redisCache.getCacheObject(CacheConstants.CUSTOMIZE_CONF);
        if (confDTOList != null && !confDTOList.isEmpty()) {
            return confDTOList;
        }
        return new ArrayList<>();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int paySalary(List<GarmentProductionUserPay> userPay) {
        if (userPay == null || userPay.isEmpty()) {
            return 0;
        }
        String userId = ShiroUtils.getSysUser().getId();
        for (GarmentProductionUserPay garmentProductionUserPay : userPay) {
            garmentProductionUserPay.setUpdateBy(userId);
            garmentProductionUserPay.setUpdateTime(new Date());
            garmentProductionUserPay.setPayTime(new Date());
            garmentProductionUserPay.setCreateTime(new Date());
            garmentProductionUserPay.setCreateBy(userId);
            garmentProductionUserPayMapper.insertGarmentProductionUserPay(garmentProductionUserPay);
        }
        // 更新编菲表的发放状态
        List<Long> upIds = userPay.stream().map(GarmentProductionUserPay::getUserId).collect(Collectors.toList());
        JSONObject param = new JSONObject();
        param.put("upIds", upIds);
        param.put("payStatus", 1);
        param.put("settlementTime", DateUtil.format(userPay.get(0).getSettlementTime(), "yyyy-MM"));
        garmentProductionBianfeiService.updatePayStatus(param);
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int paySalaryCancel(List<GarmentProductionUserPay> payRecordDTOS) {
        List<Long> upIds = payRecordDTOS.stream().map(GarmentProductionUserPay::getUserId).collect(Collectors.toList());
        for (GarmentProductionUserPay payRecordDTO : payRecordDTOS) {
            JSONObject param = new JSONObject();
            param.put("upIds", Collections.singletonList(payRecordDTO.getUserId()));
            param.put("payStatus", 0);
            param.put("settlementTime", DateUtil.format(payRecordDTO.getSettlementTime(), "yyyy-MM"));
            garmentProductionBianfeiService.updatePayStatus(param);
        }
        return garmentProductionUserPayMapper.deleteGarmentProductionUserPayByIds(upIds.toArray(new Long[0]));
    }

    @Override
    public List<GarmentProductionUserPay> paySalaryRecord(GarmentProductionPayRecordDTO userPayParam) {
        return garmentProductionUserPayMapper.selectList(userPayParam);
    }

    @Override
    public String paySalaryTotal(GarmentProductionPayRecordDTO userPayParam) {
        return garmentProductionUserPayMapper.paySalaryTotal(userPayParam);
    }

    @Override
    public List<GarmentProductionUserPay> paySalaryList(GarmentProductionPayRecordDTO userPayParam) {
        List<GarmentProductionUserPay> list = garmentProductionUserPayMapper.paySalaryList(userPayParam);
        // 查询计件工资
        List<Long> upIds = list.stream().map(GarmentProductionUserPay::getUserId).collect(Collectors.toList());

        JSONObject param = new JSONObject();
        String settleTimeStr = userPayParam.getSettlementTime();
        param.put("upIds", upIds);
        param.put("settlementTime", settleTimeStr);
        List<Map<String, String>> cntList = garmentProductionBianfeiService.qryCntSalaryByUserIds(param);
        Map<Long, String> cntMap = new HashMap<>();
        for (Map<String, String> map : cntList) {
            cntMap.put(Long.parseLong(String.valueOf(map.get("userId"))), String.valueOf(map.get("settleMoney")));
        }


        Object cacheObject = redisCache.getCacheObject(CacheConstants.CUSTOMIZE_CONF);
        // 计件工资要减去已发放的
        List<GarmentProductionUserPay> payList = garmentProductionUserPayMapper.selectListByUpIds(upIds);
        Map<Long, String> payMap = payList.stream().filter(m -> settleTimeStr.equals(DateUtil.format(m.getSettlementTime(), "yyyy-MM")))
                .collect(Collectors.toMap(GarmentProductionUserPay::getUserId, GarmentProductionUserPay::getCountSalary));
        for (GarmentProductionUserPay garmentProductionUserPay : list) {
            double totalPay = 0.0;
            String allCnt = Objects.isNull(cntMap.get(garmentProductionUserPay.getUserId())) ? "0" : cntMap.get(garmentProductionUserPay.getUserId());
            String payCnt = Objects.isNull(payMap.get(garmentProductionUserPay.getUserId())) ? "0" : payMap.get(garmentProductionUserPay.getUserId());
            String cntSalary = StringUtils.roundDoubleToString(Double.parseDouble(allCnt) - Double.parseDouble(payCnt), 2);
            garmentProductionUserPay.setCountSalary(cntSalary);
            totalPay += Double.parseDouble(cntSalary);
            if (garmentProductionUserPay.getDynamicData() == null) {
                if (Objects.nonNull(cacheObject)) {
                    List<GarmentProductionCustomizeConfDTO> confDTOList = (List<GarmentProductionCustomizeConfDTO>) cacheObject;
                    JSONArray jsonArray = new JSONArray();
                    for (GarmentProductionCustomizeConfDTO confDTO : confDTOList) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("payItemName", confDTO.getPayItemName());
                        jsonObject.put("payItemLabel", confDTO.getPayItemLabel());
                        jsonObject.put("payValue", 0);
                        jsonArray.add(jsonObject);
                    }
                    garmentProductionUserPay.setDynamicData(jsonArray.toJSONString());
                }
            } else {
                JSONArray array = JSONArray.parseArray(garmentProductionUserPay.getDynamicData());
                for (Object o : array) {
                    JSONObject jsonObject = (JSONObject) o;
                    // todo : 暂时advancePay为减项，以后需要通过配置来判断哪个是减项
                    if (jsonObject.getString("payItemLabel").equals("advancePay")) {
                        totalPay -= Double.parseDouble(jsonObject.getString("payValue"));
                    } else {
                        totalPay += Double.parseDouble(jsonObject.getString("payValue"));
                    }
                }
            }
            garmentProductionUserPay.setTotalSalary(totalPay + "");
            garmentProductionUserPay.setSettlementTime(DateUtil.parse(userPayParam.getSettlementTime(), "yyyy-MM"));
        }
        return list;
    }

    @Override
    public JSONObject paySalaryListSatistics(GarmentProductionPayRecordDTO userPayParam) {
        // 总工资
        List<GarmentProductionUserPay> list = this.paySalaryList(userPayParam);
        JSONObject res = new JSONObject();
        double sum = 0.0;
        double cntSum = 0.0;
        for (GarmentProductionUserPay garmentProductionUserPay : list) {
            double salary = Double.parseDouble(garmentProductionUserPay.getTotalSalary());
            double cntSalary = Double.parseDouble(garmentProductionUserPay.getCountSalary());
            sum += salary;
            cntSum += cntSalary;
        }
        res.put("totalSalary", sum);
        res.put("cntSalary", cntSum);
        return res;
    }

    @Override
    public JSONObject settlementStatisticsByQuantity(GarmentProductionPayCntParam userPayParam) {
        List<GarmentPayByCntResp> resps = this.settlementListByQuantity(userPayParam);
        JSONObject res = new JSONObject();
        double cntCum = 0.0;
        double paySum = 0.0;
        double settleSum = 0.0;
        double unSettleSum = 0.0;
        for (GarmentPayByCntResp resp : resps) {
            double pay = Double.parseDouble(resp.getPayMoney());
            double settle = Double.parseDouble(resp.getSettleMoney());
            double unSettle = Double.parseDouble(resp.getUnSettleMoney());
            paySum += pay;
            settleSum += settle;
            unSettleSum += unSettle;
            cntCum += settle + unSettle;
        }
        res.put("cntCum", StringUtils.formatDouble(cntCum));
        res.put("paySum", StringUtils.formatDouble(paySum));
        res.put("settleSum", StringUtils.formatDouble(settleSum));
        res.put("unSettleSum", StringUtils.formatDouble(unSettleSum));
        return res;
    }

    @Override
    public List<GarmentPayDetailResp> settlementDetailViewList(GarmentProductionPayDetailParam detailParam) {
        List<GarmentPayDetailResp> resps = garmentProductionBianfeiService.qryPayDetail(detailParam);
        for (GarmentPayDetailResp resp : resps) {
            if (resp.getStatus().equals("0")) {
                resp.setStatus("2");
            }
            // 已结算 已发放
            if (resp.getStatus().equals("1")) {
                if ("1".equals(resp.getPayStatus())) {
                    resp.setStatus("4");
                } else {
                    resp.setStatus("3");
                }
            }
        }
        return resps;
    }

    @Override
    public JSONObject settlementDetailViewStatistics(GarmentProductionPayDetailParam userPayParam) {
        List<GarmentPayDetailResp> resps = this.settlementDetailViewList(userPayParam);
        JSONObject res = new JSONObject();
        double salarySum = 0.0;
        double settlementSum = 0.0;
        double unSettlementSum = 0.0;
        double paySum = 0.0;
        Long quantitySum = 0L;
        for (GarmentPayDetailResp resp : resps) {
            double amount = Double.parseDouble(Objects.nonNull(resp.getAmount()) ? resp.getAmount() : "0");
            if (resp.getStatus().equals("2")) {
                unSettlementSum += amount;
            }
            if (resp.getStatus().equals("3")) {
                settlementSum += amount;
            }
            if (resp.getStatus().equals("4")) {
                paySum += amount;
            }
            quantitySum += Long.parseLong(Objects.nonNull(resp.getQuantity()) ? resp.getQuantity() : "0");
        }
        salarySum = unSettlementSum + settlementSum;
        res.put("salarySum", salarySum);
        res.put("settlementSum", settlementSum);
        res.put("unSettlementSum", unSettlementSum);
        res.put("paySum", paySum);
        res.put("quantitySum", quantitySum);
        return res;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchSettlement(GarmentProductionSettleParam param) {
        String userId = ShiroUtils.getSysUser().getId();
        List<GarmentProductionBianfei> bianfeis = garmentProductionBianfeiService.selectListByIds(param.getIds());
        for (GarmentProductionBianfei bianfei : bianfeis) {
            if (StringUtils.isEmpty(param.getSalaryTime())) {
                bianfei.setSettlementTime(new Date());
            } else {
                bianfei.setSettlementTime(DateUtil.parse(param.getSalaryTime(), "yyyy-MM-dd"));
            }
            bianfei.setUpdateBy(userId);
            bianfei.setUpdateTime(new Date());
            bianfei.setSettlementStatus(1L);
            garmentProductionBianfeiService.updateGarmentProductionBianfei(bianfei);
        }
        return 1;
    }

    @Override
    public int batchSettlementCancel(List<Long> ids) {
        String userId = ShiroUtils.getSysUser().getId();
        List<GarmentProductionBianfei> bianfeis = garmentProductionBianfeiService.selectListByIds(ids);
        for (GarmentProductionBianfei bianfei : bianfeis) {
            bianfei.setSettlementTime(null);
            bianfei.setUpdateBy(userId);
            bianfei.setUpdateTime(new Date());
            bianfei.setSettlementStatus(0L);
            garmentProductionBianfeiService.updateGarmentProductionBianfei(bianfei);
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int editUpNum(GarmentProductionUpNumParam param) {
        GarmentProductionBianfei bianfei = garmentProductionBianfeiService.selectGarmentProductionBianfeiById(param.getId());
        bianfei.setUpNumber(param.getQuantity());
        bianfei.setUpTime(DateUtil.parse(param.getUpTime(), "yyyy-MM-dd HH:mm:ss"));
        bianfei.setRemark(param.getRemark());
        garmentProductionBianfeiService.updateGarmentProductionBianfei(bianfei);
        // 更新工资月份
        GarmentProductionOrder order = garmentProductionOrderMapper.selectGarmentProductionOrderById(bianfei.getOrderId());
        order.setSalaryMonth(param.getSalaryMonth());
        garmentProductionOrderMapper.updateGarmentProductionOrder(order);
        return 1;
    }

    @Override
    public int delUpNum(GarmentProductionUpNumParam param) {
        return garmentProductionBianfeiService.deleteGarmentProductionBianfeiById(param.getId());
    }

    @Override
    public List<GarmentPayByCntResp> totalSalaryExport(GarmentProductionPayCntParam userPayParam) {
        List<GarmentPayByCntResp> resps = this.settlementListByQuantity(userPayParam);
        for (GarmentPayByCntResp resp : resps) {
            if (resp.getStatus().equals("0")) {
                resp.setStatusStr("未上数");
            }
            if (resp.getStatus().equals("1")) {
                resp.setStatusStr("未结算");
            }
            if (resp.getStatus().equals("2")) {
                resp.setStatusStr("部分结算");
            }
            if (resp.getStatus().equals("3")) {
                resp.setStatusStr("已结算");
            }
        }
        return resps;
    }

    @Override
    public List<GarmentPayDetailResp> cntSalaryExport(GarmentProductionPayDetailParam detailParam) {
        List<GarmentPayDetailResp> resps = this.settlementDetailViewList(detailParam);
        return resps;
    }

    @Override
    public List<GarmentPayStyleCodeAndProcessResp> settlementListByStyleCodeOrProcess(GarmentStyleCodeAndProcessParam param) {
        List<GarmentPayStyleCodeAndProcessResp> resps = garmentProductionUserPayMapper.settlementListByStyleCodeOrProcess(param);
        return resps;
    }

    @Override
    public List<GarmentProductionUserPay> paySalaryRecordExport(GarmentProductionPayRecordDTO userPayParam) {
        return null;
    }

    @Override
    public String unSettlementCnt(GarmentStyleCodeAndProcessParam param) {
        double cnt = 0.0;
        List<GarmentPayStyleCodeAndProcessResp> resps = this.settlementListByStyleCodeOrProcess(param);
        for (GarmentPayStyleCodeAndProcessResp resp : resps) {
            String quantity = resp.getQuantity();
            cnt += Double.parseDouble(quantity);
        }
        return StringUtils.roundDoubleToString(cnt, 2);
    }


}
